package com.daodao.daodaoschedule.application.service;

import com.daodao.daodaoschedule.application.service.jobhandler.BabeWeekJob;
import com.daodao.daodaoschedule.domain.wechat.WechatAccount;
import com.daodao.daodaoschedule.domain.wechat.WechatSendConfig;
import com.daodao.daodaoschedule.infrastructure.constant.WechatMessageTypeEnum;
import com.daodao.daodaoschedule.infrastructure.util.JacksonUtil;
import com.daodao.daodaoschedule.infrastructure.util.StringUtil;
import com.github.kevinsawicki.http.HttpRequest;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mal
 * @date 2023-02-15 15:14
 */
@Service
@AllArgsConstructor
public class WechatMessageSendService {

    private static final Logger logger = LoggerFactory.getLogger(WechatMessageSendService.class);

    public static final String MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";

    public static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";




    private final WechatSendConfigService wechatSendConfigService;

    private final WechatAccountService wechatAccountService;


    public void sendMessage(String openId, WechatMessageTypeEnum messageType, Long accountId, Map<String, Object> data) {

        WechatSendConfig messageTemplate = wechatSendConfigService.getMessageTemplate(messageType, accountId);
        if (messageTemplate == null) {
            throw new IllegalStateException("没有配置相应的模板信息");
        }
        WechatAccount account = getWechatToken(accountId);
        if (account == null) {
            throw new IllegalStateException("获取微信accessToken失败");
        }

        String dataStr = StringUtil.formatTemplate(messageTemplate.getDataContent(), data);

        Map<String, Object> sendMap = new HashMap<>();
        sendMap.put("touser", openId);
        sendMap.put("template_id", messageTemplate.getTemplateId());
        sendMap.put("data", JacksonUtil.readJson2Object(dataStr, Map.class));
        sendMap.put("topcolor", messageTemplate.getTopColor());

        HttpRequest messageRequest = HttpRequest
                .get(MESSAGE_URL + account.getAccessToken())
                .connectTimeout(5000)
                .readTimeout(10000)
                .acceptGzipEncoding().uncompress(true)
                .send(JacksonUtil.writeObj2Json(sendMap));

        logger.info("messageId = {},{},{}", messageTemplate.getId(), messageRequest.code(), messageRequest.body());





    }


    private WechatAccount getWechatToken(Long accountId) {

        WechatAccount wechatAccount = wechatAccountService.getByAccountId(accountId);
        if (wechatAccount == null) {
            logger.error("getWechatToken ,cannot find WechatAccount");
            return null;
        }

        if (wechatAccount.getAccessToken() != null && wechatAccount.getExpireTime() != null && wechatAccount.getExpireTime().isAfter(LocalDateTime.now())) {
            return wechatAccount;
        }


        String url = TOKEN_URL + "?grant_type=client_credential&appid=" + wechatAccount.getAppId()
                + "&secret=" + wechatAccount.getAppSecret();

        HttpRequest request = HttpRequest
                .get(url)
                .connectTimeout(5000)
                .readTimeout(10000)
                .acceptGzipEncoding().uncompress(true);

        if (request.ok()) {
            String body = request.body();
            logger.info("获取的token信息为:{}", body);
            BabeWeekJob.TokenResponse tokenResponse = JacksonUtil.readJson2Object(body, BabeWeekJob.TokenResponse.class);
            if (tokenResponse == null) {
                logger.error("getWechatToken ,cannot get weixin response");
                return null;
            }
            wechatAccount.updateAccessToken(tokenResponse.getAccessToken(), tokenResponse.getExpiresIn());
            wechatAccountService.updateAccount(wechatAccount);

            return wechatAccount;
        }
        return null;
    }
}
